﻿using System;
using System.IO;
using System.Threading;
using OdaOperation.Core.Parameters;
using OdaOperation.Extends;
using Teigha.Core;
using Teigha.TD;

namespace OdaOperation.Core.Creators
{
    /// <summary>
    /// 修剪创建者
    /// </summary>
    public class TrimmingCreator
    {
        private string m_orginFile; // 原始文件路径
        private DbOperation m_operation; // 数据库操作对象

        /// <summary>
        /// 构造函数，初始化原始文件路径和数据库操作对象
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="orgin"></param>
        public TrimmingCreator(DbOperation operation, string orgin)
        {
            m_orginFile = orgin;
            m_operation = operation;
        }

        /// <summary>
        /// 裁剪方法，接受一组裁剪参数并执行裁剪操作
        /// </summary>
        /// <param name="paramter"></param>
        public void Trimming(params TrimmingItemParameter[] paramter)
        {
            foreach (TrimmingItemParameter trimmingItemParameter in paramter)
            {
                // 复制原始文件到指定路径，并覆盖已存在的文件
                File.Copy(m_orginFile, trimmingItemParameter.File, overwrite: true);
                // 从文件中读取数据库对象
                OdDbDatabase database = m_operation.ReadFile(trimmingItemParameter.File).Database;
                try
                {
                    MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId); // 开始内存事务
                                                                                                                                       // 创建空间过滤器对象
                    OdDbSpatialFilter odDbSpatialFilter = OdDbSpatialFilter.createObject();
                    // 创建矩阵对象
                    OdGeMatrix2d odGeMatrix2d = new OdGeMatrix2d();
                    // 设置平移向量，用于裁剪坐标系
                    odGeMatrix2d.setTranslation(new OdGeVector2d(0.0 - trimmingItemParameter.Min.X, 0.0 - trimmingItemParameter.Min.Y));
                    // 创建定义点数组，定义裁剪范围
                    OdGePoint2dArray definition = new OdGePoint2dArray
                {
                    new OdGePoint2d(trimmingItemParameter.Min.X, trimmingItemParameter.Min.Y),
                    new OdGePoint2d(trimmingItemParameter.Min.X, trimmingItemParameter.Max.Y),
                    new OdGePoint2d(trimmingItemParameter.Max.X, trimmingItemParameter.Max.Y),
                    new OdGePoint2d(trimmingItemParameter.Max.X, trimmingItemParameter.Min.Y),
                    new OdGePoint2d(trimmingItemParameter.Min.X, trimmingItemParameter.Min.Y)
                };
                    // 设置空间过滤器的定义
                    odDbSpatialFilter.setDefinition(definition);
                    // 创建矩阵对象，用于转换坐标系
                    OdGeMatrix3d odGeMatrix3d = new OdGeMatrix3d();
                    odGeMatrix3d.setTranslation(new OdGeVector3d(0.0 - trimmingItemParameter.Min.X, 0.0 - trimmingItemParameter.Min.Y, 0.0));
                    // 创建范围对象，用于裁剪范围计算
                    OdGeExtents3d odGeExtents3d = new OdGeExtents3d(trimmingItemParameter.Min.ToGePoint3D(), trimmingItemParameter.Max.ToGePoint3D());
                    // 创建块表记录对象
                    OdDbBlockTableRecord odDbBlockTableRecord = BlockTableRecordCreator.CreateOdDbBlockTableRecord(database, "F-大样底图" + Guid.NewGuid().ToString("N"));
                    // 获取模型空间的块表记录对象
                    OdDbBlockTableRecord odDbBlockTableRecord2 = database.getModelSpaceId().openObject() as OdDbBlockTableRecord;
                    // 创建对象迭代器
                    OdDbObjectIterator odDbObjectIterator = odDbBlockTableRecord2.newIterator();
                    // 遍历模型空间的实体对象
                    while (!odDbObjectIterator.done())
                    {
                        // 获取实体对象
                        OdDbEntity odDbEntity = odDbObjectIterator.entity(OpenMode.kForWrite);
                        // 创建范围对象，用于实体边界计算
                        OdGeExtents3d extents = new OdGeExtents3d();
                        // 获取实体的几何边界
                        odDbEntity.getGeomExtents(extents);
                        // 计算裁剪范围与实体边界的交集
                        OdGeExtents3d.IntersectionStatus intersectionStatus = odGeExtents3d.intersectWith(extents);
                        // 如果没有交集，则删除实体对象
                        if (intersectionStatus == OdGeExtents3d.IntersectionStatus.kIntersectNot)
                        {
                            odDbEntity.erase();
                        }
                        else
                        {
                            // 如果是直线对象，则执行分割操作
                            OdDbLine odDbLine = odDbEntity as OdDbLine;
                            if (odDbLine != null)
                            {
                                Spilt(trimmingItemParameter, odDbLine, trimmingItemParameter.IsMove ? odGeMatrix3d : null);
                            }
                            // 如果是文本对象，则根据交集状态执行操作
                            else if (odDbEntity is OdDbText || odDbEntity is OdDbMText)
                            {
                                if (intersectionStatus == OdGeExtents3d.IntersectionStatus.kIntersectOpOut)
                                {
                                    odDbEntity.erase();
                                }
                                else
                                {
                                    OdRxObject pObj = odDbEntity.clone();
                                    OdDbEntity pEntity = OdDbEntity.cast(pObj);
                                    odDbEntity.erase();
                                    odDbBlockTableRecord.appendOdDbEntity(pEntity);
                                }
                            }
                            // 对于其他类型的实体对象，执行克隆并添加到新的块表记录对象中
                            else
                            {
                                OdRxObject pObj2 = odDbEntity.clone();
                                OdDbEntity pEntity2 = OdDbEntity.cast(pObj2);
                                odDbEntity.erase();
                                odDbBlockTableRecord.appendOdDbEntity(pEntity2);
                            }
                        }

                        odDbObjectIterator.step();
                    }

                    // 创建块参照对象
                    OdDbBlockReference odDbBlockReference = OdDbBlockReference.createObject();
                    odDbBlockReference.setDatabaseDefaults(database);
                    odDbBlockTableRecord2.appendOdDbEntity(odDbBlockReference);
                    odDbBlockReference.setBlockTableRecord(odDbBlockTableRecord.objectId());
                    // 如果需要移动块参照对象，则设置块变换矩阵
                    if (trimmingItemParameter.IsMove)
                    {
                        odDbBlockReference.setBlockTransform(odGeMatrix3d);
                    }

                    // 添加空间过滤器到块参照对象
                    TD_Db.addFilter(odDbBlockReference, odDbSpatialFilter);
                    // 如果名称不为空，则创建文本对象
                    if (!string.IsNullOrWhiteSpace(trimmingItemParameter.Name))
                    {
                        // 初始化默认字体样式
                        OdDbObjectId odDbObjectId = TextStyleCreator.InitDefaultsFont(database);
                        OdDbMText odDbMText = OdDbMText.createObject();
                        if (odDbObjectId != null)
                        {
                            odDbMText.setTextStyle(odDbObjectId);
                        }

                        odDbMText.setTextHeight(trimmingItemParameter.FontSize);
                        odDbMText.setDatabaseDefaults(database);
                        odDbMText.setContents(trimmingItemParameter.Name);
                        OdGeExtents3d extents2 = new OdGeExtents3d();
                        odDbBlockTableRecord2.appendOdDbEntity(odDbMText);
                        OdGePoint3d odGePoint3d = new OdGePoint3d((trimmingItemParameter.Min.X + trimmingItemParameter.Max.X) * 0.5, trimmingItemParameter.Min.Y - trimmingItemParameter.FontSize * 0.5, 0.0);
                        odDbMText.setLocation(odGePoint3d);
                        odDbMText.setLayer("0");
                        odDbMText.setAttachment(OdDbMText.AttachmentPoint.kTopCenter);
                        LineCreator lineCreator = new LineCreator(database, "0");
                        odDbMText.getGeomExtents(extents2);
                        double num = odDbMText.actualWidth();
                        OdGePoint3d odGePoint3d2 = new OdGePoint3d(odGePoint3d).Add(new OdGeVector3d((0.0 - num) * 0.5 - trimmingItemParameter.FontSize, (0.0 - odDbMText.actualHeight()) * 1.25, 0.0));
                        OdGePoint3d odGePoint3d3 = new OdGePoint3d(odGePoint3d).Add(new OdGeVector3d(num * 0.5 + trimmingItemParameter.FontSize, (0.0 - odDbMText.actualHeight()) * 1.25, 0.0));
                        // 如果需要移动文本对象，则应用块变换矩阵
                        if (trimmingItemParameter.IsMove)
                        {
                            odDbMText.transformBy(odGeMatrix3d);
                            lineCreator.CreateLine(odGePoint3d2, odGePoint3d3).transformBy(odGeMatrix3d);
                            lineCreator.CreateLine(odGePoint3d2.Add(new OdGeVector3d(0.0, (0.0 - odDbMText.actualHeight()) * 0.15, 0.0)), odGePoint3d3.Add(new OdGeVector3d(0.0, (0.0 - odDbMText.actualHeight()) * 0.15, 0.0))).transformBy(odGeMatrix3d);
                        }
                        else
                        {
                            lineCreator.CreateLine(odGePoint3d2, odGePoint3d3);
                            lineCreator.CreateLine(odGePoint3d2.Add(new OdGeVector3d(0.0, (0.0 - odDbMText.actualHeight()) * 0.15, 0.0)), odGePoint3d3.Add(new OdGeVector3d(0.0, (0.0 - odDbMText.actualHeight()) * 0.15, 0.0)));
                        }
                    }

                    // 停止内存事务
                    MemoryManager.GetMemoryManager().StopTransaction(value);
                }
                catch (Exception)
                {
                    throw;
                }

                // 清除数据库中的所有未使用对象
                database.PurgeAll();
                // 将数据库写入文件
                database.writeFile(trimmingItemParameter.File, SaveType.kDwg, DwgVersion.kDHL_1032);
            }
        }

        // 分割弧线方法
        private void Spilt(TrimmingItemParameter item, OdDbArc arc)
        {
            // 此处可以添加弧线分割逻辑
        }

        // 分割三维多段线方法
        private void Spilt(TrimmingItemParameter item, OdDb3dPolyline dPolyline)
        {
            // 此处可以添加三维多段线分割逻辑
        }

        // 分割直线方法
        private static void Spilt(TrimmingItemParameter item, OdDbLine line, OdGeMatrix3d matrix)
        {
            OdGePoint3d odGePoint3d = new OdGePoint3d();
            line.getStartPoint(odGePoint3d);
            OdGePoint3d odGePoint3d2 = new OdGePoint3d();
            line.getEndPoint(odGePoint3d2);
            // 对直线进行裁剪，确保起点和终点在裁剪范围内
            if (odGePoint3d.x > odGePoint3d2.x)
            {
                if (odGePoint3d.x > item.Max.X)
                {
                    odGePoint3d.x = item.Max.X;
                }

                if (odGePoint3d2.x < item.Min.X)
                {
                    odGePoint3d2.x = item.Min.X;
                }
            }
            else
            {
                if (odGePoint3d2.x > item.Max.X)
                {
                    odGePoint3d2.x = item.Max.X;
                }

                if (odGePoint3d.x < item.Min.X)
                {
                    odGePoint3d.x = item.Min.X;
                }
            }

            if (odGePoint3d.y > odGePoint3d2.y)
            {
                if (odGePoint3d.y > item.Max.Y)
                {
                    odGePoint3d.y = item.Max.Y;
                }

                if (odGePoint3d2.y < item.Min.Y)
                {
                    odGePoint3d2.y = item.Min.Y;
                }
            }
            else
            {
                if (odGePoint3d2.y > item.Max.Y)
                {
                    odGePoint3d2.y = item.Max.Y;
                }

                if (odGePoint3d.y < item.Min.Y)
                {
                    odGePoint3d.y = item.Min.Y;
                }
            }

            // 如果需要应用坐标系变换，则对直线进行变换
            if (matrix != null)
            {
                line.setStartPoint(odGePoint3d.transformBy(matrix));
                line.setEndPoint(odGePoint3d2.transformBy(matrix));
            }
            else
            {
                line.setStartPoint(odGePoint3d);
                line.setEndPoint(odGePoint3d2);
            }
        }
    }

}